﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jayden.Dll.Cards.Poker;
using System.Windows.Forms;
using Jayden.Dll.Cards.Poker.Enums;
using System.IO;
using System.Threading;
using Jayden.Dll.Cards;
using System.Drawing.Imaging;
using Jayden.Dll.Cards.Drawing;

namespace Jayden.Windows.PokerClient
{
	public class WindowsPokerClient : Jayden.Dll.Cards.Poker.PokerClient
	{
		public LoginForm LoginForm;
		public PokerLobbyForm LobbyForm;
		private Guid m_Guid = Guid.NewGuid();

		private Dictionary<string, PokerClientForm> m_Tables = new Dictionary<string,PokerClientForm>();
		private Dictionary<string, TournamentLobbyForm> m_Tournaments = new Dictionary<string, TournamentLobbyForm>();

		public PokerClientForm this[string tableName]
		{
			get
			{
				PokerClientForm table;
				if (m_Tables.TryGetValue(tableName, out table))
					return table;
				return null;
			}
		}

		public WindowsPokerClient() : this("127.0.0.1") { }
		public WindowsPokerClient(string host) : this(host, PokerProtocol.DefaultPort) { }
		public WindowsPokerClient(string host, int port) : base(host, port) { }

		public override void OnClientConnected()
		{
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				LoginForm.LoginEnabled = true;
			});
		}

		public override void OnClientLogin(string login)
		{
			if (File.Exists("table." + login + ".png"))
			{
				PlayerImage image = new PlayerImage("table." + login + ".png");
				SendTableImage(image);
			}
			else if (File.Exists("table.default.png"))
			{
				PlayerImage image = new PlayerImage("table.default.png");
				SendTableImage(image);
			}
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				LoginForm.LoginEnabled = true;
				LoginForm.Hide();
				LobbyForm = new PokerLobbyForm();
				LobbyForm.Client = this;
				LobbyForm.Text = "Connected as " + Login + " - Lobby";
				Lobby(PokerLimit.NoLimit, PokerType.TexasHoldem, 0, ulong.MaxValue, 0, ulong.MaxValue, "EUR|USD|POK", 0, byte.MaxValue, 0, byte.MaxValue);
				LobbyForm.Show();
			});
		}

		public override void OnClosedCards(string tableName, Dll.Cards.CardList cards)
		{
			OnServerMessage("(" + tableName + ") " + Login + " received closed cards [" + cards.ToString() + "].");
		}

		public override void OnShowCards(string tableName, Dll.Cards.CardList cards)
		{
			//OnServerMessage("(" + tableName + ") Show " + cards.ToString() + ".");
		}

		public override void OnClientMessage(string message)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				File.AppendAllLines(m_Guid.ToString() +  ".log", new string[] { DateTime.Now.ToString() + "\t" + message });
				string tableName = string.Empty;
				if (message.StartsWith("("))
				{
					int index = message.IndexOf(")");
					tableName = message.Substring(1, index - 1);
					message = message.Substring(index + 1);
				}
				if (m_Tables.TryGetValue(tableName, out tableForm))
				{
					tableForm.WriteLine(message.Trim());
				}
			});
		}

		public override void OnServerMessage(string message)
		{
			OnClientMessage(message);
		}

		public override void OnAction(string tableName, ulong call, ulong raise, ulong allin, int timeOut)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					if (m_Tables.TryGetValue(tableName, out tableForm))
					{
						tableForm.CallAmount = call;
						tableForm.RaiseAmount = raise;
						tableForm.AllInAmount = allin;
						if (tableForm.DoAutoAction())
							return;
						tableForm.SetActionControlVisible(true);
						Thread timer = new Thread(delegate()
						{
							try
							{
								Thread.Sleep(timeOut);
								LoginForm.BeginInvoke((MethodInvoker)delegate()
								{
									tableForm.SetActionControlVisible(false);
								});
							}
							catch (Exception e)
							{

							}
							tableForm.TimerThread = null;
						});
						timer.Start();
						tableForm.TimerThread = timer;
					}
				}
			});
		}

		public override void OnInitTable(PokerTableView view)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					PokerCurrency currency = PokerCurrency.GetCurrency(view.Currency);
					if (!m_Tables.TryGetValue(view.TableName, out tableForm))
					{
						tableForm = new PokerClientForm(this, view);
						m_Tables.Add(view.TableName, tableForm);
						tableForm.Show();
						tableForm.TopMost = true;
						tableForm.TopMost = false;
					}
					else
					{
						if (view.CurrentAction != tableForm.PokerTable.View.CurrentAction && tableForm.SeatTimerThread != null)
						{
							tableForm.PokerTable.SeatStartTime = DateTime.MinValue;
							tableForm.PokerTable.SeatEndTime = DateTime.MinValue;
							tableForm.SeatTimerThread.Abort();
						}
						tableForm.CallAmount = view.CallAmount;
						tableForm.RaiseAmount = view.MinRaiseAmount;
						if (tableForm.PokerTable.View.Street != view.Street)
							tableForm.UncheckAutoActions(false);
						tableForm.PokerTable.View = view;
						tableForm.Refresh();
					}
					int me = tableForm.PokerTable.Me;
					if(view.Ante > 0)
						tableForm.Text = "Connected as " + Login + " - " + view.TableName + " (" + currency.ToString(view.SmallBlind) + "/" + currency.ToString(view.BigBlind) + " ante " + currency.ToString(view.Ante) + ") " + view.Limit + " " + view.Type;
					else
						tableForm.Text = "Connected as " + Login + " - " + view.TableName + " (" + currency.ToString(view.SmallBlind) + "/" + currency.ToString(view.BigBlind) + ") " + view.Limit + " " + view.Type;
					if (me != -1)
					{
						tableForm.SetAutoPostActionControlVisible(false);
						if (view.Seats[me].State == PokerSeatState.SittingOut)
							tableForm.SitOutChecked = true;
						else if (view.Seats[me].State == PokerSeatState.Waiting && view.Seats[me].Stack > 0)
							tableForm.SetAutoPostActionControlVisible(true);
						ulong meBet = view.Seats[me].Bet;
						tableForm.AllInAmount = view.Seats[me].Stack;
						ulong maxBet = 0;
						for (int c = 0; c < view.Seats.Length; c++)
						{
							if (view.Seats[c] != null)
							{
								ulong bet = view.Seats[c].Bet;
								if (maxBet < bet)
									maxBet = bet;
							}
						}
						tableForm.CallAmount = maxBet - meBet;
						bool hide = true;
						for (int c = 0; c < view.PlayersLeftToTalk.Length; c++)
						{
							if (me == view.PlayersLeftToTalk[c])
							{
								tableForm.SetAutoActionControlVisible(true);
								hide = false;
							}
						}
						if(hide)
							tableForm.SetAutoActionControlVisible(false);
					}
					if (tableForm.PokerTable.LastButton != view.Button)
					{
						tableForm.PokerTable.MyFoldedCards = null;
						tableForm.PokerTable.LastButton = view.Button;
						tableForm.Pot = new PokerPot();
					}
					tableForm.SitOutVisible = (Login != null && view.IsSitted(Login));
				}
			});
		}

		public void LeaveTable(string tableName)
		{
			lock (m_Tables)
			{
				m_Tables.Remove(tableName);
			}
		}

		public override void OnClientLoginFail(string login, string reason)
		{
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				MessageBox.Show(LoginForm, "Unable to login with user " + login + " : " + reason + ".", "Login failed");
			});
			OnClientConnected();
		}

		public override void OnLobby(List<PokerTableInfo> cashGames, List<PokerTournamentInfo> tournaments)
		{
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				LobbyForm.SetCashGamesList(cashGames);
				LobbyForm.SetTournamentsList(tournaments);
			});
		}

		public override void OnActionShow(string tableName, int timeOut)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					if (m_Tables.TryGetValue(tableName, out tableForm))
					{
						tableForm.SetAutoActionControlVisible(false);
						if (LobbyForm.AutoMuckLosingHand)
							SendActionShow(tableName, false);
						else
						{
							tableForm.SetShowHideCardsVisible(true);
							Thread timer = new Thread(delegate()
							{
								try
								{
									Thread.Sleep(timeOut);
									LoginForm.BeginInvoke((MethodInvoker)delegate()
									{
										tableForm.SetShowHideCardsVisible(false);
									});
								}
								catch (Exception e)
								{

								}
								tableForm.TimerThread = null;
							});
							timer.Start();
							tableForm.TimerThread = timer;
						}
					}
				}
			});
		}

		public override void OnTableImage(string playerName, System.Drawing.Image image)
		{
			image.Save("table." + playerName + ".png", ImageFormat.Png);
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					foreach(PokerClientForm tableForm in m_Tables.Values)
						tableForm.PokerTable.Refresh();
				}
			});
		}

		public override void OnTimer(string tableName, int seatIndex, int timeOut)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					if (m_Tables.TryGetValue(tableName, out tableForm))
					{
						tableForm.SetSeatTimer(seatIndex, timeOut);
					}
				}
			});
		}

		public override void OnException(Exception e)
		{
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				try
				{
					OnClientMessage("==== Exception Catched ====");
					OnClientMessage(e.Message);
					string[] stackTrace = e.StackTrace.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
					foreach (string line in stackTrace)
						OnClientMessage(line);
					OnClientMessage("===========================");
				}
				finally
				{
					MessageBox.Show(LoginForm, e.Message, "Exception.", MessageBoxButtons.OK, MessageBoxIcon.Error);
					Application.Exit();
				}
			});
		}

		public override void OnClientDisconnected()
		{
			OnClientMessage("==== Client Disconnected ====");
		}

		public override void OnChatMessage(string tableName, string playerName, string message)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					if (m_Tables.TryGetValue(tableName, out tableForm))
					{
						tableForm.WriteChat(playerName, message);
					}
				}
			});
		}

		public override void OnBankroll(ulong bankroll)
		{
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				MessageBox.Show(LobbyForm, "Bankroll for " + Login + " : " + PokerCurrency.EUR.ToString(bankroll) + ".", "Bankroll");
			});
		}

		public override void OnActionDone(string tableName, string playerName, PokerActionType action, ulong amount)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					if (m_Tables.TryGetValue(tableName, out tableForm))
					{
						if (action == PokerActionType.Bet || action == PokerActionType.Raise)
							tableForm.UncheckAutoActions(true);
					}
				}
			});
		}

		public override void OnTournamentFinished(string tournamentName, int position, ulong amount, PokerCurrency currency)
		{
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				string format = string.Empty;
				if (amount > 0)
					format = string.Format(" and won {0}", currency.ToString(amount));
				MessageBox.Show(LoginForm, string.Format("You finished {0} in tournament '{1}'{2}.", (position + 1), tournamentName, format), tournamentName);
			});
		}

		public override void OnBlindGoesUp(string tableName, ulong smallBlind, ulong bigBlind, ulong ante)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					if (m_Tables.TryGetValue(tableName, out tableForm))
					{
						tableForm.BlindGoesUp(smallBlind, bigBlind, ante);
					}
				}
			});
		}

		public override void OnTournamentLobby(string tournamentName, bool isRegistred)
		{
			TournamentLobbyForm tournamentForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tournaments)
				{
					if (!m_Tournaments.TryGetValue(tournamentName, out tournamentForm))
					{
						tournamentForm = new TournamentLobbyForm();
						tournamentForm.Text = tournamentName;
						tournamentForm.Client = this;
						tournamentForm.TournamentName = tournamentName;
						tournamentForm.IsRegistered = isRegistred;
						tournamentForm.Init();
						tournamentForm.Show();
						m_Tournaments.Add(tournamentName, tournamentForm);
					}
				}
			});
		}

		public override void OnTournamentRegister(string tournamentName)
		{
			TournamentLobbyForm tournamentForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tournaments)
				{
					if (m_Tournaments.TryGetValue(tournamentName, out tournamentForm))
					{
						tournamentForm.IsRegistered = true;
						tournamentForm.Init();
					}
				}
				MessageBox.Show(tournamentForm, "You've registered to tournament '" + tournamentName + "'.", tournamentName);
			});
		}

		public override void OnTournamentUnregister(string tournamentName)
		{
			TournamentLobbyForm tournamentForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tournaments)
				{
					if (m_Tournaments.TryGetValue(tournamentName, out tournamentForm))
					{
						tournamentForm.IsRegistered = false;
						tournamentForm.Init();
					}
				}
				MessageBox.Show(tournamentForm, "You've un-registered from tournament '" + tournamentName + "'.", tournamentName);
			});
		}

		public void LeaveTournamentLobby(string tournamentName)
		{
			lock (m_Tournaments)
			{
				m_Tournaments.Remove(tournamentName);
			}
		}

		public PokerClientForm FindByTournamentName(string tournamentName)
		{
			lock (m_Tables)
			{
				foreach (PokerClientForm form in m_Tables.Values)
				{
					if (form.PokerTable.View != null && form.PokerTable.View.TournamentName == tournamentName && form.PokerTable.Me != -1)
						return form;
				}
			}
			return null;
		}

		public override void OnTournamentLobbyPlayers(string tournamentName, List<KeyValuePair<string, ulong>> players)
		{
			TournamentLobbyForm tournamentForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tournaments)
				{
					if (m_Tournaments.TryGetValue(tournamentName, out tournamentForm))
					{
						tournamentForm.SetPlayers(players);
					}
				}
			});
		}

		public override void OnTournamentLobbyBettingStructure(string tournamentName, List<PokerTournamentConfiguration.BettingStructureEntry> bettingStructure)
		{
			TournamentLobbyForm tournamentForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tournaments)
				{
					if (m_Tournaments.TryGetValue(tournamentName, out tournamentForm))
					{
						tournamentForm.SetBettingStructure(bettingStructure);
					}
				}
			});
		}

		public override void OnTournamentLobbyPayoutStructure(string tournamentName, List<PokerTournamentConfiguration.PayoutEntry> payoutStructure)
		{
			TournamentLobbyForm tournamentForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tournaments)
				{
					if (m_Tournaments.TryGetValue(tournamentName, out tournamentForm))
					{
						tournamentForm.SetPayoutStructure(payoutStructure);
					}
				}
			});
		}

		public override void OnActionPost(string tableName, bool smallAndBig, int timeOut)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					if (m_Tables.TryGetValue(tableName, out tableForm))
					{
						tableForm.SetAutoPostActionControlVisible(false);
						if (tableForm.AutoWaitBigBlind)
							SendActionPost(tableName, false);
						else
						{
							tableForm.MustPostBoth = smallAndBig;
							tableForm.SetPostActionControlVisible(true);
							Thread timer = new Thread(delegate()
							{
								try
								{
									Thread.Sleep(timeOut);
									LoginForm.BeginInvoke((MethodInvoker)delegate()
									{
										tableForm.SetPostActionControlVisible(false);
									});
								}
								catch (Exception e)
								{

								}
								tableForm.TimerThread = null;
							});
							timer.Start();
							tableForm.TimerThread = timer;
						}
					}
				}
			});
		}

		public override void OnAskBuyIn(string tableName, int seatIndex, ulong bankroll, ulong minBuyIn, ulong maxBuyIn)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					if (m_Tables.TryGetValue(tableName, out tableForm))
					{
						bool sitted = (seatIndex == tableForm.PokerTable.Me);
						SitInCashGameForm sitInCashGame = new SitInCashGameForm();
						sitInCashGame.Text = sitted ? "Buy-in" : "Re-buy";
						sitInCashGame.Bankroll = bankroll;
						sitInCashGame.Stack = sitted ? tableForm.PokerTable.View.Seats[seatIndex].Stack : 0;
						sitInCashGame.Currency = PokerCurrency.GetCurrency(tableForm.PokerTable.View.Currency);
						if (sitInCashGame.ShowDialog(tableForm) == System.Windows.Forms.DialogResult.OK)
						{
							PokerTableView.PokerTableSeatView seat = tableForm.PokerTable.View.Seats[seatIndex];
							if (seat == null && !tableForm.SitOutVisible)
							{
								Sit(tableForm.PokerTable.View.TableName, seatIndex, sitInCashGame.Amount);
							}
							else if (sitted)
								ReBuy(tableForm.PokerTable.View.TableName, sitInCashGame.Amount);
						}
					}
				}
			});
		}

		public override void OnTournamentRebuy(string tournamentName, int timeOut)
		{
			PokerClientForm tableForm = null;
			LoginForm.BeginInvoke((MethodInvoker)delegate()
			{
				lock (m_Tables)
				{
					tableForm = FindByTournamentName(tournamentName);
					if (tableForm != null)
					{
						tableForm.SetRebuyControlVisible(true, false);
						Thread timer = new Thread(delegate()
						{
							try
							{
								Thread.Sleep(timeOut);
								LoginForm.BeginInvoke((MethodInvoker)delegate()
								{
									tableForm.SetRebuyControlVisible(false);
								});
							}
							catch (Exception e)
							{

							}
							tableForm.TimerThread = null;
						});
						timer.Start();
						tableForm.TimerThread = timer;
					}
				}
			});
		}
	}
}
